package org.mindrive.system.service.system;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.mindrive.system.collection.system.QuartzJobEntity;
import org.mindrive.system.collection.system.UserEntity;
import org.mindrive.system.core.MindriveException;
import org.mindrive.system.parameter.system.CreateQuartzJobParameter;
import org.mindrive.system.parameter.system.SearchQuartzJobParameter;
import org.mindrive.system.parameter.system.UpdateQuartzJobParameter;
import org.mindrive.system.service.BaseService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class QuartzJobService extends BaseService {

	@Autowired
	private Scheduler scheduler;

	public void create(CreateQuartzJobParameter input) {
		UserEntity loginUser = getLoginUser();

		QueryWrapper<QuartzJobEntity> query = new QueryWrapper<QuartzJobEntity>();
		query.eq("job_class_name", input.getJobClassName());
		long count = quartzJobDao.count(query);
		if (count > 0) {
			throw new MindriveException("该定时任务类名已存在");
		}
		QuartzJobEntity entity = new QuartzJobEntity();
		entity.setJobClassName(input.getJobClassName());
		entity.setCronExpression(input.getCronExpression());
		entity.setParameter(input.getParameter());
		entity.setDescription(input.getDescription());
		entity.setStatus(input.getStatus());
		entity.setCreatedAt(new Date());
		entity.setCreator(loginUser.getUserId());
		quartzJobDao.save(entity);
		if (QUARTZ_JOB_STATUS_NORMAL.equals(input.getStatus())) {
			this.schedulerAdd(entity.getId(), entity.getJobClassName().trim(), entity.getCronExpression().trim(),
					entity.getParameter(), entity.getDescription().trim());
		}

	}

	public void edit(String id, UpdateQuartzJobParameter input) {
		QuartzJobEntity entity = quartzJobDao.getById(id);
		if (entity == null) {
			throw new MindriveException("未找到对应的实体。" + id);
		}
		if (QUARTZ_JOB_STATUS_NORMAL.equals(input.getStatus())) {
			schedulerDelete(entity.getId());
			schedulerAdd(entity.getId(), input.getJobClassName().trim(), input.getCronExpression().trim(),
					input.getParameter(), input.getDescription());
		} else {
			schedulerPause(entity.getId());
		}
		QuartzJobEntity update = new QuartzJobEntity();
		update.setId(id);
		update.setJobClassName(input.getJobClassName());
		update.setCronExpression(input.getCronExpression());
		update.setParameter(input.getParameter());
		update.setDescription(input.getDescription());
		update.setStatus(input.getStatus());
		quartzJobDao.updateById(update);

	}

	public void delete(String id) {
		QuartzJobEntity entity = quartzJobDao.getById(id);
		if (entity == null) {
			throw new MindriveException("未找到对应的实体。" + id);
		}
		schedulerDelete(entity.getId());
		quartzJobDao.removeById(id);

	}

	public void resume(String id) {
		QuartzJobEntity entity = quartzJobDao.getById(id);
		if (entity == null) {
			throw new MindriveException("未找到对应的实体。" + id);
		}
		schedulerDelete(entity.getId());
		schedulerAdd(entity.getId(), entity.getJobClassName().trim(), entity.getCronExpression().trim(),
				entity.getParameter(), entity.getDescription());

		QuartzJobEntity update = new QuartzJobEntity();
		update.setId(id);
		update.setStatus(QUARTZ_JOB_STATUS_NORMAL);
		quartzJobDao.updateById(update);
	}

	public void pause(String id) {

		QuartzJobEntity entity = quartzJobDao.getById(id);
		if (entity == null) {
			throw new MindriveException("未找到对应的实体。" + id);
		}
		schedulerPause(entity.getId());

		QuartzJobEntity update = new QuartzJobEntity();
		update.setId(id);
		update.setStatus(QUARTZ_JOB_STATUS_STOP);
		quartzJobDao.updateById(update);

	}

	public QuartzJobEntity detail(String id) {
		return quartzJobDao.getById(id);
	}

	public Map<String, Object> search(SearchQuartzJobParameter parameter) {

		QueryWrapper<QuartzJobEntity> query = new QueryWrapper<QuartzJobEntity>();

		String jobClassName = parameter.getJobClassName();
		if (jobClassName != null && !"".equals(jobClassName)) {
			query.like("job_class_name", jobClassName);
		}
		String status = parameter.getStatus();
		if (status != null && !"".equals(status)) {
			query.eq(STATUS, status);
		}
		String description = parameter.getDescription();
		if (description != null && !"".equals(description)) {
			query.like("description", description);
		}

		int count = quartzJobDao.count(query);

		List<QuartzJobEntity> list = null;
		Page<QuartzJobEntity> page = page(QuartzJobEntity.class, parameter.getPageSize(), parameter.getCurrentPage());
		if (page == null) {
			list = quartzJobDao.list(query);
		} else {
			quartzJobDao.page(page, query);
			list = page.getRecords();
		}

		Map<String, Object> result = new HashMap<String, Object>();
		result.put(COUNT, count);
		result.put(LIST, list);
		return result;
	}

	/**
	 * 添加定时任务
	 * 
	 * @param jobClassName
	 * @param cronExpression
	 * @param parameter
	 */
	private void schedulerAdd(String id, String jobClassName, String cronExpression, String parameter,
			String description) {
		try {

//			Keycloak kc = keycloakHelper.getCustomerInstance(ALFRESCO_USER_ID,
//					ALFRESCO_USER_PASSWORD);
//			AccessTokenResponse tokenResponse = kc.tokenManager().getAccessToken();
//			String token = tokenResponse.getToken();

			// 启动调度器
			scheduler.start();

			// 构建job信息
			JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(JobKey.jobKey(id))
					.usingJobData("parameter", parameter).withDescription(description).build();

			// 表达式调度构建器(即任务执行的时间)
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

			// 按新的cronExpression表达式构建一个新的trigger
			CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(TriggerKey.triggerKey(id))
					.withSchedule(scheduleBuilder).build();

			scheduler.scheduleJob(jobDetail, trigger);
		} catch (SchedulerException e) {
			throw new MindriveException("创建定时任务失败", e);
		} catch (Exception e) {
			throw new MindriveException("后台找不到该类名：" + jobClassName, e);
		}
	}

	/**
	 * 删除定时任务
	 * 
	 * @param jobClassName
	 */
	private void schedulerDelete(String id) {
		try {
			scheduler.pauseTrigger(TriggerKey.triggerKey(id));
			scheduler.unscheduleJob(TriggerKey.triggerKey(id));
			scheduler.deleteJob(JobKey.jobKey(id));
		} catch (Exception e) {
			log.error("删除定时任务失败。", e);
			throw new MindriveException("删除定时任务失败");
		}
	}

	private void schedulerPause(String id) {
		try {
			scheduler.pauseJob(JobKey.jobKey(id));
		} catch (Exception e) {
			log.error("暂停定时认识失败。", e);
			throw new MindriveException("暂停定时任务失败");
		}
	}

	private static Job getClass(String classname) throws Exception {
		Class<?> class1 = Class.forName(classname);
		return (Job) class1.newInstance();
	}

	public void schedulerAdd(QuartzJobEntity entity) {
		try {
			// 启动调度器
			scheduler.start();

			// 构建job信息
			JobDetail jobDetail = JobBuilder.newJob(getClass(entity.getJobClassName()).getClass())
					.withIdentity(JobKey.jobKey(entity.getId())).usingJobData("parameter", entity.getParameter())
					.withDescription(entity.getDescription()).build();

			// 表达式调度构建器(即任务执行的时间)
			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(entity.getCronExpression());

			// 按新的cronExpression表达式构建一个新的trigger
			CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(TriggerKey.triggerKey(entity.getId()))
					.withSchedule(scheduleBuilder).build();

			scheduler.scheduleJob(jobDetail, trigger);
		} catch (SchedulerException e) {
			throw new MindriveException("创建定时任务失败", e);
		} catch (Exception e) {
			throw new MindriveException("后台找不到该类名：" + entity.getJobClassName(), e);
		}

	}

	/**
	 * 删除定时任务
	 * 
	 * @param jobClassName
	 */
	public void schedulerDelete(QuartzJobEntity entity) {
		try {
			scheduler.pauseTrigger(TriggerKey.triggerKey(entity.getId()));
			scheduler.unscheduleJob(TriggerKey.triggerKey(entity.getId()));
			scheduler.deleteJob(JobKey.jobKey(entity.getId()));
		} catch (Exception e) {
			log.error("删除定时任务失败。", e);
			throw new MindriveException("删除定时任务失败");
		}
	}

}
